import { Inject, Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import * as TelegramBot from 'node-telegram-bot-api';
import { Repository } from 'typeorm';
import { ETransactionType, ReferralCode, Subscribe, Transaction, User } from '../../model';
import { ChangeNickName, MessageSubs, addCodeTelegramCode, getCodeTelegramId } from './dto/models.dto';

@Injectable()
export class TraderService {
    constructor(
        @InjectRepository(Subscribe)
        private subscribeRepository: Repository<Subscribe>,
        @InjectRepository(Transaction)
        private transactionRepository: Repository<Transaction>,
        @InjectRepository(User)
        private userRepository: Repository<User>,
        @InjectRepository(ReferralCode)
        private referralCodeRepository: Repository<ReferralCode>,
        @Inject('TelegramBot')
        private bot: TelegramBot
    ) {}

    private formatMessage(message: string, nickname: string) {
        if (message.length < 100) return message + `\n\nfrom ${nickname} <3`;
        const regex = /(.{100})/g;
        message.match(regex).join('\n');
        return message + `\n\nfrom ${nickname} <3`;
    }

    /**
     * Автоматическое списываение денег с балансов подписчиков каждого трейдера
     * Если при попытке списать деньги с пользователя, баланс уходит в минис, то срабатывает триггер в самопальной модельке
     * в папке model в проекте, где триггер выплевывает ошибку и try catch ее по идее обрабатывает
     * Используется stream.on ~ stream.end - для того чтобы не захламлять память, а проводить "некие" манипуляции с каждой записью и забывать (по крайней в мере в мечтах)
     */
    async autoPay() {
        try {
            const query = this.subscribeRepository.createQueryBuilder('subscribe').select(['*']);

            const stream = await query.stream();

            stream.on('data', async (subscribe: Subscribe) => {
                if (!subscribe.status) {
                    const transaction = new Transaction({
                        userTelegramId: subscribe.userTelegramId,
                        typeTransaction: ETransactionType.Payment,
                        amount: subscribe.sum,
                        result: false,
                    });
                    await this.transactionRepository.save(transaction);

                    try {
                        const user = await this.userRepository.findOneBy({
                            telegramId: subscribe.userTelegramId,
                        });
                        user.balance -= subscribe.sum;
                        await this.userRepository.save(user);

                        await this.transactionRepository.update(
                            {
                                id: transaction.id,
                            },
                            { result: true }
                        );
                        await this.subscribeRepository.update({ id: subscribe.id }, { status: true });

                        //Спаммерские оповещение об успешной оплате
                        // await this.bot.sendMessage(
                        // 	subscribe.userTelegramId,
                        // 	'Оплата за подписку прошла успешно',
                        // );
                    } catch (error) {
                        await this.bot.sendMessage(
                            subscribe.userTelegramId,
                            'Оплата за подписку не прошла, пополните счет'
                        );
                        console.log(`У ${subscribe.userTelegramId} не хватает денег`);
                    }
                }
            });

            stream.on('end', () => {
                console.log('Списание окончено');
                return true;
            });
        } catch (error) {
            console.log(error);
            return false;
        }
    }

    async sendMessage(infoMessage: MessageSubs) {
        try {
            const query = this.subscribeRepository
                .createQueryBuilder('subscribe')
                .select(['*'])
                .where('subscribe.traderTelegramId = :id', {
                    id: `${infoMessage.traderTelegramId}`,
                });

            const nickname = await this.userRepository.findOneBy({
                telegramId: infoMessage.traderTelegramId,
            });

            const stream = await query.stream();

            stream.on('data', async (subscribe: Subscribe) => {
                if (subscribe.status) {
                    await this.bot.sendMessage(
                        subscribe.userTelegramId,
                        this.formatMessage(infoMessage.message, nickname.nickname)
                    );
                }
            });
            return true;
        } catch (error) {
            console.log(error);
            return false;
        }
    }

    async getAllReferralCodes(user: getCodeTelegramId) {
        try {
            const codes = await this.referralCodeRepository
                .createQueryBuilder('rc')
                .select(['rc.referralCode'])
                .where('rc.userTelegramId = :id', { id: user.telegramId })
                .getRawMany();

            return codes;
        } catch (error) {
            console.log(error);
            return new Error('Error Get referral codes');
        }
    }

    async addReferralCode(data: addCodeTelegramCode) {
        try {
            await this.referralCodeRepository.save(
                new ReferralCode({
                    userTelegramId: data.telegramId,
                    referralCode: data.nameCode,
                    makeReferral: true,
                })
            );
            return true;
        } catch (error) {
            console.log(error);
            return false;
        }
    }

    async changeNickname(data: ChangeNickName) {
        try {
            await this.userRepository.update({ telegramId: data.telegramId }, { nickname: data.newNickname });
            return true;
        } catch (error) {
            console.log(error);
            return false;
        }
    }
}
